<?php
	/**
	* Global model
	*/
	class GlobalModel extends Object
	{
		/**
		 * default constructor
		 */
		function __construct($current_controller = null)
		{
			global $object;
			
			if (!is_object($current_controller))
			{
				$name = ereg_replace("([A-Z])", "_\\1", $current_controller);
				$name = ereg_replace("^_", "", $name);
				$name = strtolower($name);
			}
			else
			{
				$name = $current_controller->name;
			}
			
			if (!isset($this->stored_procedure_list)) $this->stored_procedure_list = $object->config->stored_procedure_prefix.$name.'_list';
			if (!isset($this->stored_procedure_list_paged)) $this->stored_procedure_list_paged = $object->config->stored_procedure_prefix.$name.'_list_paged';
			if (!isset($this->stored_procedure_update)) $this->stored_procedure_update = $object->config->stored_procedure_prefix.$name.'_update';
			if (!isset($this->stored_procedure_get)) $this->stored_procedure_get = $object->config->stored_procedure_prefix.$name.'_get';
			if (!isset($this->stored_procedure_delete)) $this->stored_procedure_delete = $object->config->stored_procedure_prefix.$name.'_delete';
			if (!isset($this->stored_procedure_insert)) $this->stored_procedure_insert = $object->config->stored_procedure_prefix.$name.'_insert';
			if (!isset($this->table_name)) $this->table_name = $object->config->table_prefix.$name;
			if (!isset($this->database_config)) $this->database_config = 'db_config_default';
		}		
		
		/**
		 * Default database config if not specified in model
		 *
		 * @var string
		 */
		public $database_config = 'db_config_default';
    	
		/**
		 * Stored procedures for listing items
		 *
		 * @var string
		 */
		public $stored_procedure_list = null;
		
		/**
		 * Stored procedures for listing items by pages
		 *
		 * @var string
		 */
		public $stored_procedure_list_paged = null;
		
		/**
		 * Stored procedures for inserting an item
		 *
		 * @var string
		 */
		public $stored_procedure_insert = null;
		
		/**
		 * Stored procedures for updating an item
		 *
		 * @var string
		 */
		public $stored_procedure_update = null;
		
		/**
		 * Stored procedures for getting an item by primary key
		 *
		 * @var string
		 */
		public $stored_procedure_get = null;
		
		/**
		 * Stored procedures for deleting an item
		 *
		 * @var string
		 */
		public $stored_procedure_delete = null;
		
		
		//DATABASE ROUTINES
		
		/**
 		* Updates or inserts $data array
 		* @param array $data data array for update 
 		* @param string $stored_procedure stored procedure (default: null)
 		* @param array $out_parameters out parameters (default: null)
 		* @return boolean update result
 		*/
		function Update($data, $stored_procedure = null, &$out_parameters = NULL)
		{
			if ($this->Validate($data))
			{
				if ($this->config->use_database)
				{
					return $this->data_engine->Update($data, $this, $stored_procedure, $out_parameters);
				}
				else 
				{
					throwError(DB_ERROR,'The use_database variable is set to false');
				}
			}
			else 
			{
				return false;
			}
		}
		
		/**
 		* Gets the record by the specified primary key
 		* @param integer $id primary key
 		* @param string $stored_procedure: stored procedure (default: null)
 		* @return object DB record
 		*/
		function Get($id, $stored_procedure = null)
		{
			if ($this->config->use_database)
			{
				return  $this->data_engine->Get($this, $id, $stored_procedure);
			}
			else 
			{
				throwError(DB_ERROR,'The use_database variable is set to false');
			}
		}
		
		/**
 		* Gets records array
 		* @param array $parameters parameters for the procedure
 		* @param string $stored_procedure stored procedure name (default: null)
 		* @param array $out_parameters out parameters (default: null)
  		* @return objects DB records' array
  		*/
		function ListItems($parameters = null, $stored_procedure = null, &$out_parameters = null)
		{
			if ($this->config->use_database)
			{
				return $this->data_engine->ListItems($this, $parameters, $stored_procedure, $out_parameters);
			}
			else 
			{
				throwError(DB_ERROR,'The use_database variable is set to false');
			}
		}
		
		/**
 		* Gets paged records array
 		* @param array $parameters parameters for the procedure
 		* @param string $stored_procedure stored procedure name (default: null)
 		* @param array $out_parameters out parameters (default: null)
  		* @return objects DB records' array
  		*/
		function ListItemsPaged($parameters = null, $stored_procedure = null, &$out_parameters = null)
		{
			if ($this->config->use_database)
			{
				if (empty($stored_procedure)) $stored_procedure = $this->stored_procedure_list_paged;
				return $this->data_engine->ListItems($this, $parameters, $stored_procedure, $out_parameters);
			}
			else 
			{
				throwError(DB_ERROR,'The use_database variable is set to false');
			}
		}
		
		/**
 		* Deletes object 
 		* @param array $parameters parameters for the procedure
 		* @param string $stored_procedure stored procedure name (default: null)
  		* @return resource Result resource identifier
 		*/
		function Delete($parameters, $stored_procedure = null)
		{
			if ($this->config->use_database)
			{
				return $this->data_engine->Delete($parameters, $this, $stored_procedure);		
			}
			else 
			{
				throwError(DB_ERROR,'The use_database variable is set to false');
			}
		}
			
		/**
 		* Executes a stored procedure or sql statement
 		* $parameters: parameters array
 		* $stored_procedure: stored procedure - optional
 		* $sql: sql string
 		* @return boolean delete result
 		*/
		function Execute($parameters, $stored_procedure = null, $sql = null)
		{
			return $this->data_engine->Execute($this, $parameters, $stored_procedure, $sql);		
		}
		
		
		//DATABASE ROUTINES END
		
		/**
 		* Get Primary key from db_structure
 		* 
 		* @return string primary key name or error if not found
 		*/
		function GetPrimaryKey()
		{
			foreach ($this->db_structure as $key=>$value)
			{
				if (isset($value[primary_key]) && (!(empty($value[primary_key]))) && $value[primary_key] =='True')
				{
					return $value['name'];
				}
				else
				{
					throwError(ERROR, 'No primary key defined in Model '.$this->name.'. Please check <strong>table_structure</strong> array.');
					return false;
				}
			}
		}
		
		/**
 		* Loads default values from db_structure
 		* 
 		* @return array results' array, false if not found or is empty in $db_structure array
 		*/
		function LoadDefaultsValues()
		{
			$result = false;
			if (!(empty($this->db_structure)))
			{
				foreach ($this->db_structure as $key=>$value)
				{
				    //Debugger::VarDump($key.':'.$value.' | ');
					if (isset($value[default_value]))
					{
						$result[$key] = $value[default_value];
					}
				}
			}
			return $result;
		}
		
		/**
		 * Checks if the model has required fields
		 */
		function CheckRequiredFields()
		{
			foreach ($this->db_structure as $key=>$value)
			{
				if ($key['not_null'] == true)
				{
					return true;
				}
			}
			return false;
		}
		
		/**
 		* Validates data towards db structure and sets appropriate values in $this->validation_errors if necessary
 		* @param array $data data array
 		* @return false true if found errors or false if not
 		*/
		//TODO: to improve code
		function Validate($data)
		{
			$this->validation_errors = array();
			$_SESSION['validations_errors'][$this->name] = array();
			
			if (!empty($data))
			{
				foreach ($data as $key=>$value)
				{
					//if not null;
					if (($this->db_structure[$key][not_null]==true) && ($this->db_structure[$key]['type']!='bit') && (((empty($value)) && ($value!==0) && ($value!=='0') && ($value!=0)) || ($value=='')))
					{
						$this->validation_errors[$key] = LANG_CANNOT_BE_NULL;
					}
					
					//check max length
					if ((isset($this->db_structure[$key][length]))&&(strlen($value) > $this->db_structure[$key][length]))
					{
						$this->validation_errors[$key] = LANG_TOO_LONG.'. '.LANG_MAX_LENGTH.': '.$this->db_structure[$key][length];
					}
					
					//check min length
					if ((isset($this->db_structure[$key][min_length]))&&(strlen($value) < $this->db_structure[$key][min_length]))
					{
						$this->validation_errors[$key] = LANG_TOO_SHORT.'. '.LANG_MIN_LENGTH.': '.$this->db_structure[$key][min_length];
					}
					
					//check max value
					if ((in_array($this->db_structure[$key][type], $this->data_engine->engine->database_formats[numeric_formats]))&&($value > $this->db_structure[$key][max_value])&&(!empty($this->db_structure[$key][max_value])))
					{
						$this->validation_errors[$key] = LANG_TOO_BIG.'. '.LANG_MAX_VALUE.': '.$this->db_structure[$key][max_value];
					}
	
					//check min value
					if ((in_array($this->db_structure[$key][type], $this->data_engine->engine->database_formats[numeric_formats]))&&($value < $this->db_structure[$key][min_value])&&(!empty($this->db_structure[$key][min_value])))
					{
						$this->validation_errors[$key] = LANG_TOO_SMALL.'. '.LANG_MIN_VALUE.': '.$this->db_structure[$key][min_value];
					}
					
					//check data type
					//if numeric
					if ((in_array($this->db_structure[$key][type], $this->data_engine->engine->database_formats[numeric_formats]))&&(!is_numeric(str_replace(',', '.', $value)) && (!empty($value))))
					{
						$this->validation_errors[$key] = LANG_NOT_NUMERIC;
					}
					//if decimal
					if (($this->db_structure[$key][type]=='decimal') && (!filter_var(str_replace(',', '.', $value), FILTER_VALIDATE_FLOAT)) && (!empty($value)))
					{
						$nValue = (int)$value;
						if (!empty($nValue))
							$this->validation_errors[$key] = LANG_NOT_DECIMAL;
					}
					//if date
					if ((in_array($this->db_structure[$key][type], $this->data_engine->engine->database_formats[date_formats]))&&(!eregi("^([0-9]){4}[[:punct:]]([0-9]){2}[[:punct:]]([0-9]){1,2}([ ]([0-9]){2}[:]([0-9]){2}[:]([0-9]){2}){0,1}$", $value)) && (!eregi("^([0-9]){1,2}[[:punct:]]([0-9]){2}[[:punct:]]([0-9]){4}([ ]([0-9]){2}[:]([0-9]){2}[:]([0-9]){2}){0,1}$", $value)) && (!empty($value)))
					{
						$this->validation_errors[$key] = LANG_NOT_DATE;
					}
	
					//validates vs regular expression
					if ((isset($this->db_structure[$key][regexp]))&&(!eregi("{$this->db_structure[$key][regexp]}", $value)) && (!empty($value)))
					{
						$this->validation_errors[$key] = LANG_NOT_REGEXP;
					}
					
					
					//sub_type check
					//if email
					if (($this->db_structure[$key][sub_type]=='email') && (!filter_var($value, FILTER_VALIDATE_EMAIL)) && (!empty($value)))
					{
						$this->validation_errors[$key] = LANG_NOT_EMAIL;
					}
					//if url
					if (($this->db_structure[$key][sub_type]=='url') && (!filter_var($value, FILTER_VALIDATE_URL)) && (!empty($value)))
					{
						$this->validation_errors[$key] = LANG_NOT_URL;
					}
					//if ip
					if (($this->db_structure[$key][sub_type]=='ip') && (!filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE)) && (!empty($value)))
					{
						$this->validation_errors[$key] = LANG_NOT_IP;
					}
				}
			}
			
			//check if we have erors
			if (empty($this->validation_errors)) 
			{
				return true;
			}
			else 
			{
				$_SESSION['validations_errors'][$this->name] = $this->validation_errors;
				return false;
			}
		}
		
		
		//SQL SCHEME FUNCTIONS
		
		/**
		 * Gets DB structure
		 *
		 * @return array
		 */
		function GetSchema(array $options)
		{
			return  $this->data_engine->GetSchema($options);
		}

		/**
		 * Gets tables list
		 *
		 * @return array
		 */
		function GetTables(array $options)
		{
			return  $this->data_engine->GetTables($options);
		}
		
		/**
		 * Gets SQL object code
		 *
		 * @param string $obj_name name of the object
		 * @return array SQL-code of the database objectsn by the line
		 */
		function GetSqlObjectCode($obj_name)
		{
			return  $this->data_engine->GetSqlObjectCode($obj_name);
		}
		
		/**
		 * Gets SQL object names
		 *
		 * @param string $obj_name part of the name of the SQL-object to pick out only necessary objects
		 * @return array SQL-object names of the database
		 */
		function GetSqlObjectNames($obj_name='')
		{
			return  $this->data_engine->GetSqlObjectNames($obj_name);
		}
	}
?>